#include "sys_thread.hpp"

std::vector<CThread *> CThread::_thread_list;
CCriticalSection  CThread::cri_sec;

CThread::CThread(std::string thread_mame, 
                ThreadType thread_type = ThreadType::INDEPENDENT,
                ThreadStartType thrd_start_type = ThreadStartType::instant_create) 
                :  _name(thread_mame), _type(thread_type), _thrd_start_type(thrd_start_type)
{
    _running = false;

    if(_type == ThreadType::SLAVE)
        _sync_lock = true;
    else _sync_lock = false;

    _thread_list.push_back(this);
}

void CThread::start()
{
    if (_running)
    {
        printf("[Thread Manager] Tried to start %s but it was already running!\n",
                _name.c_str());
        return;
    }

    switch (_thrd_start_type)
    {
    case ThreadStartType::instant_create:
        _htd = CreateThread(NULL, 128, (LPTHREAD_START_ROUTINE)_thread_t<CThread>,
                        this, (DWORD)0, &_thrd);   
        break;
    case ThreadStartType::suspended_create:
        _htd = CreateThread(NULL, 128, (LPTHREAD_START_ROUTINE)_thread_t<CThread>,
                        this, (DWORD)CREATE_SUSPENDED, &_thrd);   
        break;
    default:
        break;
    }

    if(_htd != NULL)
        printf("[Thread Manager] Thread %s starts successfully!\n ", _name.c_str());
    _running = true;
}

void CThread::exit()
{
    if (!_running)
    {
        printf("[Thread Manager] Tried to stop %s but it wasn't running!\n",
                _name.c_str());
        return;
    }

    _running = false;
    printf("[Thread Manager] Waiting for %s to stop...\n", _name.c_str());
    
    // windows operation
    TerminateThread(_htd, 0);
    WaitForSingleObject(_htd, 500);
    CloseHandle(_htd);
    _htd = 0;
    _thrd = 0;

    // linux operation (wait for complement) 

    printf("[Thread Manager] Done!\n");
    clean_up();
}

bool CThread::suspendThread(std::string thrd_name){
    DWORD _flag;
    for (auto &thread : _thread_list){
        if(thread->_name==thrd_name){
            _flag = SuspendThread(thread->_htd);
            if(_flag == 0){
                printf("[Thread Manager] %s Thread is suspended!\n", thread->_name.c_str());
                return true;
            }
            return false;   
        }
    }
    printf("[Thread Manager] %s Thread is NOT FOUND!\n", thrd_name.c_str());
    return false;   
}

bool CThread::resumeThread(std::string thrd_name){
    DWORD _flag;
    for (auto &thread : _thread_list){
        if(thread->_name==thrd_name){
            _flag = ResumeThread(thread->_htd);
            if(_flag > 0){
                printf("[Thread Manager] %s Thread is resumed!\n", thread->_name.c_str());
                return true;
            }
            return false;            
        }
    }
    printf("[Thread Manager] %s Thread is NOT FOUND!\n", thrd_name.c_str());
    return false;
}

void CThread::cutAllThread()
{
    for (auto &thread : _thread_list)
        thread->exit();
}

void CThread::printAllThread()
{
    for(auto &thread: _thread_list)
    {
        printf("[Thread Manager] %s thread is running...\n", thread->_name.c_str());
    }
}

void test_thread()
{   
    while (1)
    {
        printf("[Thread Manager] Tried to start\n");
        /* code */
    }
}

void CThread::_thread()
{
    init();

    /*Infinite loop*/
    while (_running)
    {
        /*Synchronize under master-slave mode*/
        if(this->_type == ThreadType::MASTER)
        {
            auto len = _thread_list.size();
            this->_sync_lock = false;
            for(auto tr(0); tr < len; tr++)
            {
                if(_thread_list[tr]->_type == ThreadType::SLAVE && !_thread_list[tr]->_sync_lock)
                {
                    this->_sync_lock = true;
                    break;
                }
            }
        }

        if(!this->_sync_lock)
        {
            /*Run the main task*/
            task();

            /*Synchronize under master-slave mode*/
            if(_type == ThreadType::INDEPENDENT) _sync_lock = false;
            else _sync_lock = true;

            if(_type == ThreadType::MASTER)
            {
                for(auto tr : _thread_list) 
                {
                    if(tr->_type == ThreadType::SLAVE)
                        tr->_sync_lock = false;
                }
            }
        }
    }
    printf("[Thread Manager] %s has stopped!\n", _name.c_str());
}

void CThread::lock()
{
    cri_sec.Lock();
}
void CThread::unlock()
{
    cri_sec.UnLock();
}